Ems 74 implement reporting analytics#46
Conversation
… clean up UI - Added admin stats endpoints in auth, event, and booking services - Implemented getDashboardStats method to aggregate statistics from all services - Updated admin dashboard to fetch and display real data from database - Removed flagged users functionality from UI and backend - Removed pending approvals button from dashboard - Fixed route paths for admin stats endpoints
- Updated /api/auth/admin/users endpoint to support search by name/email - Added role and status filters (ADMIN, USER, SPEAKER, ACTIVE, INACTIVE) - Implemented pagination with page and limit parameters (default: 10, max: 100) - Returns pagination metadata (total, totalPages, hasNextPage, hasPreviousPage) - Case-insensitive search using Prisma contains with mode insensitive
- Added /api/booking/admin/attendance-stats endpoint - Calculates average attendance percentage across all events - Only counts attendees (USER role), excludes ADMIN and SPEAKER - Returns totalRegistrations, totalAttended, and attendancePercentage - Filters bookings to only include attendees for accurate metrics
- Updated getAllUsers() to accept filters (search, role, status, page, limit) - Added pagination response type with metadata - Added getAttendanceStats() method to fetch attendance statistics - Returns both data and pagination information for user queries
- Updated Input component to use React.forwardRef - Allows parent components to access input element reference - Enables focus management for search inputs
- Moved search, filters, and pagination to backend API - Added debounced search (500ms) with focus management - Implemented pagination UI with page numbers and prev/next buttons - Stats cards now show total counts (not filtered) - Replaced Inactive Users card with Average Attendance Percentage - Only shows loading overlay on table, not full page re-render - Maintains search input focus during typing and data updates - Optimized with useCallback to prevent unnecessary re-renders
- Added /api/event/admin/reports/event-status endpoint - Returns breakdown of events by status (Published, Draft, Pending, etc.) - Calculates percentages for each status - Filters out statuses with zero events
- Added /api/booking/admin/reports/top-events endpoint - Returns top 10 events by registration count - Only counts attendees (USER role), excludes admins and speakers - Includes registrations, attendance count, and attendance percentage per event
- Added /api/auth/admin/reports/user-growth endpoint - Returns monthly user registration data - Calculates cumulative totals and new users per month - Sorted chronologically for trend analysis
- Added getReportsData() method to aggregate all reports data - Fetches dashboard stats, attendance stats, top events, event status, and user growth - Fetches event names for top events from event service - Returns comprehensive reports data structure
…ries - Removed all mock data from reports page - Implemented real-time data fetching from backend APIs - Added loading states and error handling - Added empty states for when data is not available - Updated all metrics cards to display real data (Total Events, Users, Registrations, Attendance) - Top Performing Events now shows real events with actual registrations and attendance - Event Status Distribution displays real breakdown from database - User Growth Trend shows monthly user registration data with cumulative totals - All data now fetched from database instead of hardcoded values
Related Fixes: 1. Recreated Migrations for the Booking Service 2. Recreated Migrations for Speaker Service 3. Created Migrations for Feedback Service
…-Implement-Feedback-Collection
1. Aded Speaker Join on client-side
…red event messages from speaker events page
… fix hardcoded data
…-Implement-Feedback-Collection
Summary Replaced mock data in the attendee dashboard with backend data. Added: Backend Changes (ems-services/booking-service): 1. Added service methods in booking.service.ts: - getDashboardStats(userId) - Returns statistics (registered events, upcoming events, attended events, tickets, etc.) - getUpcomingEvents(userId, limit) - Returns upcoming events with event details from event-service - getRecentRegistrations(userId, limit) - Returns recent bookings with event details 2. Added routes in booking.routes.ts: - GET /bookings/dashboard/stats - Dashboard statistics - GET /bookings/dashboard/upcoming-events?limit=5 - Upcoming events - GET /bookings/dashboard/recent-registrations?limit=5 - Recent registrations Frontend Changes (ems-client): 1. Updated API client (booking.api.ts): - Added attendeeDashboardAPI with methods for dashboard data - Methods: getDashboardStats(), getUpcomingEvents(limit), getRecentRegistrations(limit) 2. Updated attendee dashboard page (app/dashboard/attendee/page.tsx): - Removed mock data - Added state management for stats, upcoming events, and recent registrations - Added loading and error states - Fetches data from backend on component mount - Displays real data from the booking service - Added empty state messages when no data is available Features: - Dashboard statistics: registered events, upcoming events, attended events, tickets purchased/active/used, upcoming this week/next week - Upcoming events: shows events the user registered for that are in the future, with event details from event-service - Recent registrations: shows the user's most recent bookings - Loading and error states - Navigation: clicking "View" on upcoming events navigates to event details The dashboard now fetches and displays real data from the backend instead of mock data.
Fixed Issues:
1. Changed tickets to ticket (singular) — The Prisma schema uses ticket (singular, optional), not tickets (plural).
2. Removed references to booking.event.bookingStartDate — The Event model in booking-service doesn't include this field. It only has id, capacity, isActive, createdAt, and updatedAt.
3. Fixed ticket access — Changed from booking.tickets.length and booking.tickets.forEach() to booking.ticket (checking if it exists since it's optional).
4. Fixed orderBy clause — Removed the invalid event: { bookingStartDate: 'asc' } since bookingStartDate doesn't exist in the Event model. Now using createdAt: 'desc' and sorting after fetching event details from event-service.
5. Added event-service fetching — Methods now fetch event details from event-service to get bookingStartDate and other event information not stored in booking-service.
The code should now compile successfully. The booking service will:
- Use the correct Prisma relationship (ticket instead of tickets)
- Fetch event details from event-service when needed
- Handle the optional ticket relationship correctly
- Sort events properly after fetching their details from event-service
Summary
Added back buttons to all pages within app/dashboard/admin, app/dashboard/speaker, and app/dashboard/attendee (excluding the home page.tsx files).
Changes Made
1 EventDetailsPage Component (components/events/EventDetailsPage.tsx)
• Updated back button to navigate to the correct parent page based on user role:
• ADMIN → /dashboard/admin/events
• SPEAKER → /dashboard/speaker/events
• USER → /dashboard/attendee/events
1 LiveEventAuditorium Component (components/events/LiveEventAuditorium.tsx)
• Updated back buttons (header and error state) to navigate to the event details page based on user role:
• ADMIN → /dashboard/admin/events/{eventId}
• SPEAKER → /dashboard/speaker/events/{eventId}
• USER → /dashboard/attendee/events/{eventId}
Pages Verified with Back Buttons
Admin:
• ✅ events/[id]/page.tsx (uses EventDetailsPage)
• ✅ events/[id]/live/page.tsx (uses LiveEventAuditorium)
• ✅ events/create/page.tsx (already had back button)
• ✅ events/modify/[id]/page.tsx (already had back button)
• ✅ events/pending/page.tsx (already had back button)
• ✅ users/flagged/page.tsx (already had back button)
Speaker:
• ✅ events/[id]/page.tsx (uses EventDetailsPage)
• ✅ events/[id]/live/page.tsx (uses LiveEventAuditorium)
• ✅ events/create/page.tsx (already had back button)
• ✅ events/edit/[id]/page.tsx (already had back button)
Attendee:
• ✅ events/[id]/page.tsx (uses EventDetailsPage)
• ✅ events/[id]/live/page.tsx (uses LiveEventAuditorium)
All back buttons now navigate to the correct parent pages based on the user's role and the current page context.
🧪 Test Results ✅
Summary: All automated checks have been completed for this PR. |
There was a problem hiding this comment.
Pull Request Overview
This PR implements a comprehensive Python-based seeding script for the Event Management System and adds several new features to both backend services and frontend client. The changes focus on data seeding capabilities, dashboard enhancements, pagination, search/filter functionality, and improved user experience.
- Adds a modular Python seeding script for populating the system with test data (users, speakers, events, bookings, invitations, materials, and messages)
- Implements dashboard statistics endpoints across multiple microservices (auth, event, booking)
- Adds search, filtering, and pagination to various admin and speaker interfaces
- Enhances UI components with better event expiry handling and live event access controls
- Improves API client methods to support new filtering and pagination parameters
Reviewed Changes
Copilot reviewed 51 out of 54 changed files in this pull request and generated 21 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/seed.py | Main seeding orchestrator with connectivity tests and step-by-step data population |
| scripts/requirements.txt | Python dependencies (requests, faker) for seeding script |
| scripts/modules/*.py | Modular seeding components for users, events, bookings, and speaker data |
| ems-services/speaker-service/src/services/speaker-attendance.service.ts | Adds event expiry validation before allowing speaker join |
| ems-services/speaker-service/src/services/invitation.service.ts | Implements pagination and search for speaker invitations |
| ems-services/notification-service/src/consumers/ticket-event.consumer.ts | New consumer for ticket generation events with QR code email notifications |
| ems-services/notification-service/package.json | Adds qrcode dependencies for ticket QR code generation |
| ems-services/booking-service/src/services/booking.service.ts | Adds dashboard statistics methods for attendees |
| ems-services/booking-service/src/routes/admin.routes.ts | New admin endpoints for attendance stats and top events reports |
| ems-services/event-service/src/services/event.service.ts | Adds search and timeframe filtering for events |
| ems-services/auth-service/src/routes/routes.ts | New admin endpoints for user management, stats, and bulk activation |
| ems-client/lib/api/*.ts | Updates API clients with new filtering, search, and pagination parameters |
| ems-client/app/dashboard/speaker/events/page.tsx | Major refactor with pagination, search, debouncing, and improved UX |
| ems-client/app/dashboard/attendee/*.tsx | Connects to real API endpoints for dashboard data instead of mock data |
| ems-client/app/dashboard/admin/*.tsx | Implements real data loading with pagination and improved user management |
| ems-client/components/ui/input.tsx | Converts Input component to use forwardRef for better ref handling |
| ems-client/components/events/*.tsx | Adds event expiry checks and improved navigation |
Files not reviewed (1)
- ems-services/notification-service/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ({ className, type, ...props }, ref) => { | ||
| return ( | ||
| <input | ||
| type={type} | ||
| ref={ref} |
There was a problem hiding this comment.
The Input component is being converted to use React.forwardRef, but the ref is named ref which could shadow the outer ref variable if one exists. Consider using a more descriptive name like forwardedRef or ensure this pattern is consistent with your codebase standards.
| ({ className, type, ...props }, ref) => { | |
| return ( | |
| <input | |
| type={type} | |
| ref={ref} | |
| ({ className, type, ...props }, forwardedRef) => { | |
| return ( | |
| <input | |
| type={type} | |
| ref={forwardedRef} |
| const isAccepted = invitation?.status === 'ACCEPTED'; | ||
| const now = new Date(); | ||
| const eventEndDate = new Date(event.bookingEndDate); | ||
| const isEventEnded = now > eventEndDate; |
There was a problem hiding this comment.
Unused variable isEventEnded.
| const isEventEnded = now > eventEndDate; |
| if admin_token and admin_user_id and speakers and events: | ||
| speaker_emails = [s['email'] for s in speakers if s.get('email')] | ||
| if speaker_emails: | ||
| speaker_stats = seed_speaker_data( |
There was a problem hiding this comment.
Variable speaker_stats is not used.
| sys.exit(1) | ||
|
|
||
| try: | ||
| from faker import Faker |
There was a problem hiding this comment.
Import of 'Faker' is not used.
| import random | ||
| import time | ||
| import requests | ||
| import io |
There was a problem hiding this comment.
Import of 'io' is not used.
| error_data = response.json() | ||
| error_msg = error_data.get('error', response.text) | ||
| print_error(f"Admin login failed: HTTP {http_status} - {error_msg}") | ||
| except: |
There was a problem hiding this comment.
Except block directly handles BaseException.
| error_data = response.json() | ||
| error_msg = error_data.get('error', response.text) | ||
| print_error(f"Activation failed: HTTP {http_status} - {error_msg}") | ||
| except: |
There was a problem hiding this comment.
Except block directly handles BaseException.
| if response.status_code in [200, 404]: | ||
| utils.print_success("API is reachable (health check)") | ||
| return True | ||
| except: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| except requests.exceptions.ConnectionError: | ||
| utils.print_error(f"Cannot connect to {utils.AUTH_API_URL}") | ||
| return False | ||
| except: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
| error_data = response.json() | ||
| if 'already exists' in str(error_data.get('error', '')).lower(): | ||
| return False # Duplicate, not an error | ||
| except: |
There was a problem hiding this comment.
'except' clause does nothing but pass and there is no explanatory comment.
No description provided.